/**
 * @author qiuny
 * @description 绘制元素，线条，箭头，不规则形状等等
 * @class
 * @see {@link CoverEditor}
 */
import { v4 as uuidV4 } from "uuid";
import { fabric } from "fabric";
import HosooArrow from "../graphs/HosooArrow";
import LineArrow from "../graphs/LineArrow";
import LineSolidArrow from "../graphs/LineSolidArrow";

class DrawingPlugin {
    static apis = ['setDrawingType', 'setMode']
    static events = ["onDrawingComplete"];
    constructor(canvas, editor) {
        this.canvas = canvas;
        this.editor = editor;
        this.isDrawingLine = false;
        // 绘制状态，绘制结束置为false，防止二次触发绘制结束事件
        this.isDrawingLineMode = false;
        this.cusDrawingType = "";
        this.drawLineType = ""
        this.lineToDraw = null;
        this.pointerPoints = [];
        this.isMouseDown = false
        this.lastPositionIndex = 1
        this.mousePosition = { x: 0, y: 0 }
        this.bgColor = "#18a058"
        this.attribute = {}
        this._init();
    }
    _init() {
        const canvas = this.canvas;
        canvas.on("mouse:down", (evt) => {
            // 绘图模式false，直接返回
            if (!this.isDrawingLineMode) return;
            // 取消选中元素，避免绘制线条触发选中，影响绘制效果
            canvas.discardActiveObject()
            // 二次点击开启元素可选中状态
            canvas.getObjects().forEach(item => {
                item.selectable = false
                item.hasControls = false
            })

            // 鼠标监听只有符合绘制类型才会执行
            if (!["DrawPolygon","DrawPolyline", "PencilBrush","Line", "HosooArrow", "LineArrow", "LineSolidArrow"].includes(this.cusDrawingType)) return
            
            this.mousePosition = this.pointer = canvas.getPointer(evt.e)
            
            // 重新渲染
            canvas.requestRenderAll();
            this.isDrawingLine = true            
            // 标识鼠标状态
            this.isMouseDown = true
            
            let opts = {
                strokeWidth: 1,
                stroke: "rgba(2, 0, 36, 1)",
                fill: 'rgba(2, 0, 36, 1)',
                id: uuidV4()
            }
            
            switch (this.cusDrawingType) {
                case 'DrawPolygon':
                case 'DrawPolyline':
                    // Remove duplicate starting points
                    if (this.pointerPoints.length > 1) {
                        this.pointerPoints.splice(-1, 1);
                    }
                    if (this.cusDrawingType=='DrawPolyline') {
                        this.drawLineType = 'Polyline'
                        this.bgColor = ""
                    }
                    if (this.cusDrawingType=='DrawPolygon') {
                        this.drawLineType = 'Polygon'
                        this.bgColor = "#18a058"
                    }
                    
                    if (this.cusDrawingType && this.isMouseDown) {
                        this.lineToDraw = new fabric.Polyline(this.pointerPoints, {
                            objectCaching: false,
                            name: "temp",
                            fill: "",
                            stroke: 'black',
                            strokeWidth: 3,
                            originX: "center",
                            originY: "center",
                            selectable: false,
                        });
                        canvas.add(this.lineToDraw)
                        this.lineToDraw.points[this.pointerPoints.length] = { x: this.mousePosition.x, y: this.mousePosition.y };
                        this.lastPositionIndex++;
                    }

                    break;
                case 'PencilBrush':
                    this.lineToDraw = new fabric.PencilBrush(canvas)
                    canvas.freeDrawingBrush.color = this.attribute.fill || opts.fill
                    canvas.freeDrawingBrush.width = parseInt(this.attribute.strokeWidth) || opts.strokeWidth
                    // 将线段按不动间隔分开，形式为数组[10, 20, 30]
                    canvas.freeDrawingBrush.strokeDashArray = [this.attribute.strokeDashDistance]

                    break;
                case "Line":
                    // 实际绘制线类型
                    this.drawLineType = 'Line'
                    canvas.setCursor('crosshair')
                    this.pointerPoints = [this.mousePosition.x, this.mousePosition.y, this.mousePosition.x, this.mousePosition.y];
                    this.lineToDraw = new fabric.Line(this.pointerPoints, opts);
                    // this.lineToDraw.evented = false;
                    // this.lineToDraw.strokeUniform = true;
                    canvas.add(this.lineToDraw)
                    break;
                case "HosooArrow":
                case "LineSolidArrow":
                case "LineArrow":
                    let fabricObject;
                    if (this.cusDrawingType==='HosooArrow') fabricObject = HosooArrow;
                    if (this.cusDrawingType==='LineArrow') fabricObject = LineArrow;
                    if (this.cusDrawingType==='LineSolidArrow') fabricObject = LineSolidArrow;
                    opts = {
                        stroke: '#f00',
                        fill: '#f00',
                        strokeWidth: 2,
                        selectable: false,
                        hasControls: false
                    }
                    this.drawLineType = this.cusDrawingType
                    canvas.setCursor('crosshair')
                    this.pointerPoints = [this.mousePosition.x, this.mousePosition.y, this.mousePosition.x, this.mousePosition.y];
                    this.lineToDraw = new fabricObject(this.pointerPoints, opts)
                    this.lineToDraw.selectable = false;
                    this.lineToDraw.evented = false;
                    this.lineToDraw.strokeUniform = true;
                    canvas.add(this.lineToDraw)
                    canvas.selection = false
                    break;
                default:
                    break;
            }

            if (!this.lineToDraw) throw new Error("Draw failed: invalid lineType.");
        });

        canvas.on("mouse:move", (evt) => {
            if (!this.isDrawingLine || !["Polyline","Polygon","Line", "HosooArrow", "LineArrow", "LineSolidArrow"].includes(this.drawLineType)) return;
            canvas.discardActiveObject();
            const activeObject = canvas.getActiveObject();
            if (activeObject) return;
            this.mousePosition = canvas.getPointer(evt.e)
            if (this.cusDrawingType && this.isMouseDown) {
                // 绘制折线和不规则形状
                if (['DrawPolygon', 'DrawPolyline'].includes(this.cusDrawingType)) {
                    this.lineToDraw.points[this.lastPositionIndex - 1] = { x: this.mousePosition.x, y: this.mousePosition.y };
                }
                // 绘制直线
                if (['Line', 'HosooArrow', 'LineArrow', "LineSolidArrow"].includes(this.cusDrawingType)) {
                    this.lineToDraw.set({
                        x2: this.mousePosition.x,
                        y2: this.mousePosition.y
                    })
                }
            }
            canvas.renderAll();
        });

        canvas.on("mouse:dblclick", (evt) => {
            if (!this.isDrawingLine || !["Polyline","Polygon"].includes(this.drawLineType)) return;
            if (this.cusDrawingType && this.isMouseDown) {
                let drawObject;
                // 绘制折线和不规则形状
                if (['DrawPolygon', 'DrawPolyline'].includes(this.cusDrawingType)) {
                    canvas.forEachObject(function(obj) { 
                        if (obj.name=='temp') { 
                            canvas.remove(obj);
                        } 
                    })
                    // Polygon|PolyLine
                    drawObject = new fabric[this.drawLineType](this.pointerPoints,
                        {
                            objectCaching: false,
                            id: uuidV4(),
                            stroke: 'black',
                            strokeWidth:3, 
                            fill: this.bgColor,
                            originX:'center',
                            originY:'center',
                            selectable:true 
                        });
                    this.lastPositionIndex = 1
                    this.isMouseDown = false
                    this.pointerPoints = []
                    this.mousePosition = { x: 0, y: 0 }
                    canvas.add(drawObject)
                    canvas.renderAll();
                    // 双击绘制完成后，清理绘制参数，避免鼠标再次出现绘制图形
                    this.drawLineType = ""
                    this.cusDrawingType = ""
                    
                    // 绘制完成，广播事件
                    this.onDrawingComplete(drawObject)
                }
            }
        });

        // 鼠标弹起事件
        canvas.on('mouse:up', evt => {
            // 排除绘制不规则图形和折线
            if (!['DrawPolygon', 'DrawPolyline'].includes(this.cusDrawingType)) {
                if (!this.isDrawingLine) return;
                this.lineToDraw['setCoords']&&this.lineToDraw.setCoords()
                this.isDrawingLine = false
                this.onDrawingComplete(this.lineToDraw)
            }
        })

        // 监听属性完成回调，增强绘制样式
        this.editor.on('onAttributesChange', attrPramas => {
            this.attribute = attrPramas
        })
    }

    setDrawingType(params) {
        this.cusDrawingType = params;
    }

    setMode(params) {
        this.isDrawingLineMode = params;
        // 恢复元素编辑可控状态
        if (!this.isDrawingLineMode) {
            this.endRest();
        }
    }

    endRest() {
        this.canvas.getObjects().forEach(item => {
            // 排除工作区，工作区不能手动选中和控制
            if (item.id !== 'workspace') {
                item.selectable = true;
                item.hasControls = true;
            }
        })
    }

    // 绘制完成后回调函数，所有监听此回调的页面都会收到通知
    onDrawingComplete (active) {
        if (!this.isDrawingLineMode) return;
        this.editor.emit('onDrawingComplete', active)
    }

    destroy() {
        console.log('DrawLinePlugin destroy');
    }
}

export default DrawingPlugin;
